package com.studyprojectbacked.config;

import com.alibaba.fastjson2.JSONObject;
import com.studyprojectbacked.entity.RestBean;
import com.studyprojectbacked.service.AuthorizeService;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl;
import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;

import javax.sql.DataSource;
import java.io.IOException;

@Configuration
public class SecurityConfiguration {

  @Autowired
  AuthorizeService authorizeService;

  @Resource
  DataSource dataSource;

  @Bean
  public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
    return http
        // 权限
        .authorizeHttpRequests()
        .requestMatchers("/api/auth/**")
        .permitAll()
        .anyRequest()
        .authenticated()
        // 登录
        .and()
        .formLogin()
        .loginProcessingUrl("/api/auth/login")
        .successHandler(this::onAuthenticationSuccess)
        .failureHandler(this::onAuthenticationFailure)
        // 注销
        .and()
        .logout()
        .logoutUrl("/api/auth/logout")
        .logoutSuccessHandler(this::onAuthenticationSuccess)
        // 记住我
        .and()
        .rememberMe()
        .rememberMeParameter("remember")
        .tokenRepository(this.tokenRepository())
        .tokenValiditySeconds(3600 * 24 * 7) // 7天
        // 安全认值
        .and()
        .csrf()
        .disable()
        .cors()
        .configurationSource(this.configurationSource())
        // 未登录
        .and()
        .exceptionHandling()
        .authenticationEntryPoint(this::onAuthenticationFailure)
        // 构建
        .and()
        .build();
  }

  @Bean
  public AuthenticationManager authenticationManager(HttpSecurity http) throws Exception {
    return http
        .getSharedObject(AuthenticationManagerBuilder.class)
        .userDetailsService(authorizeService)
        .and()
        .build();
  }

  @Bean
  public PasswordEncoder passwordEncoder () {
    return new BCryptPasswordEncoder();
  }

  @Bean
  public PersistentTokenRepository tokenRepository() {
    JdbcTokenRepositoryImpl jToken = new JdbcTokenRepositoryImpl();
    jToken.setDataSource(dataSource);
    // 创建表(第一次启动的时候用)
    jToken.setCreateTableOnStartup(false);
    return jToken;
  }

  private CorsConfigurationSource configurationSource() {
    CorsConfiguration cors = new CorsConfiguration();
    cors.setAllowCredentials(true);
    cors.addAllowedOriginPattern("*");
    cors.addAllowedHeader("*");
    cors.addAllowedMethod("*");
    cors.addExposedHeader("*");
    UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
    source.registerCorsConfiguration("/**", cors);
    return source;
  }


  private void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException {
    response.setCharacterEncoding("UTF-8");

    if (request.getRequestURI().endsWith("/api/auth/login"))
      response.getWriter().write(
          JSONObject.toJSONString(RestBean.success("登录成功"))
      );
    else if (request.getRequestURI().endsWith("/api/auth/logout"))
      response.getWriter().write(
          JSONObject.toJSONString(RestBean.success("注销成功"))
      );
  }

  private void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException e) throws IOException {
    response.setCharacterEncoding("UTF-8");
    response.getWriter().write(
        JSONObject.toJSONString(RestBean.failure(401, e.getMessage()))
    );
  }


}
